package us.lithub.data;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import us.lithub.Util;

import android.util.Log;

/**
 * The Class WebConnector deals with all REST API connections.
 */
public class WebConnector {

	/** The Constant TAG. (used for debugging) */
	private static final String TAG = WebConnector.class.getSimpleName();	
	
	/** The web connector to return from factory*/
	private static WebConnector webConnector;

	private WebConnector() {

	}

	/**
	 * Gets the single instance of WebConnector.
	 *
	 * @return single instance of WebConnector
	 */
	public static WebConnector getInstance() {
		if (webConnector == null) {
			webConnector = new WebConnector();
		}
		return webConnector;
	}

	/**
	 * Login.
	 *
	 * @param username the username
	 * @param password the password
	 * @return the int
	 */
	public int login(String username, String password) {
		try {
			final URL url = new URL("http://" + Util.BASE_URL + "/lithub/?model=LoginPage&view=LoginPageXML&action=login&username=" + username + "&password=" + password);
			final SAXParserFactory spf = SAXParserFactory.newInstance();
			final SAXParser sp = spf.newSAXParser();	
			final XMLReader xr = sp.getXMLReader();	
			final LoginHandler handler = new LoginHandler();
			xr.setContentHandler(handler);
			Log.d(TAG, "Running parser from foo()");
			xr.parse(new InputSource(url.openStream()));
			return handler.getUserID();
		} catch (Exception e) {
			Log.e("TAG", e.getMessage());
		}
		return 0;
	}

	/**
	 * XML parser for login return data
	 */
	private class LoginHandler extends DefaultHandler {

		/** The in user id. */
		private boolean inUserID;
		
		/** The user id. */
		private int userID;

		/**
		 * Gets the user id.
		 *
		 * @return the user id
		 */
		public int getUserID() {
			return userID;
		}

		@Override
		public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
			if (qName.equals("userID")) {
				inUserID = true;
			}
		}

		@Override 
		public void characters(char ch[], int start, int length) {
			if (inUserID) {
				userID = Integer.parseInt(new String(ch, start, length));
				inUserID = false;
			}
		}
	}

	/**
	 * Lend book.
	 *
	 * @param username the username
	 * @param password the password
	 * @param receiver the receiver
	 * @param bookTitle the book title
	 * @return true, if successful
	 */
	public boolean lendBook(String username, String password, String receiver, String bookTitle) {
		try {
			String cleanBookTitle = bookTitle.replaceAll(" ", "%20");
			cleanBookTitle = cleanBookTitle.replaceAll("\"", "\\\"");
			cleanBookTitle = cleanBookTitle.replaceAll("+", "&#43;");
			final URL url = new URL("http://" + Util.BASE_URL + "/lithub/?model=UserPage&view=UserPageXML&action=LendItem&bookTitle=" + cleanBookTitle + "&usernameOfReceiver=" + receiver + "&mobile=WHAHAHA&username=" + username + "&password=" + password);
			final SAXParserFactory spf = SAXParserFactory.newInstance();
			final SAXParser sp = spf.newSAXParser();	
			final XMLReader xr = sp.getXMLReader();	
			final LendBookHandler handler = new LendBookHandler();
			xr.setContentHandler(handler);
			Log.d(TAG, "Hitting: " + url.toString());
			xr.parse(new InputSource(url.openStream()));
		} catch (Exception e) {
			Log.e(TAG, e.getMessage());
		}		
		return true;
	}

	/**
	 * Return book.
	 *
	 * @param username the username
	 * @param password the password
	 * @param ownerName the owner name
	 * @param bookTitle the book title
	 * @return true, if successful
	 */
	public boolean returnBook(String username, String password, String ownerName, String bookTitle) {
		try {
			String cleanBookTitle = bookTitle.replaceAll(" ", "%20");
			cleanBookTitle = cleanBookTitle.replaceAll("\"", "\\\"");
			final URL url = new URL("http://" + Util.BASE_URL + "/lithub/?model=UserPage&view=UserPageXML&action=ReturnItem&mobile=yes&username="+username+"&password="+password+"&bookTitle="+cleanBookTitle+"&usernameOfOwner="+ownerName);
			final SAXParserFactory spf = SAXParserFactory.newInstance();
			final SAXParser sp = spf.newSAXParser();	
			final XMLReader xr = sp.getXMLReader();	
			final LendBookHandler handler = new LendBookHandler();
			xr.setContentHandler(handler);
			Log.d(TAG, "Hitting: " + url.toString());
			xr.parse(new InputSource(url.openStream()));
		} catch (Exception e) {
			Log.e(TAG, e.getMessage());
		}		
		return true;
	}

	/**
	 * XML parser for lending return data.
	 */
	private class LendBookHandler extends DefaultHandler {

		/* (non-Javadoc)
		 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
		 */
		@Override
		public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
			Log.d(TAG, "Opening tag: " + qName);
		}

		/* (non-Javadoc)
		 * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
		 */
		@Override 
		public void characters(char ch[], int start, int length) { 
			String chars = new String(ch, start, length);
			Log.d(TAG, "Text: " + chars);
		}
	}

	/**
	 * Adds the book.
	 *
	 * @param username the username
	 * @param password the password
	 * @param isbn the isbn
	 * @return true, if successful
	 */
	public boolean addBook(String username, String password, String isbn) {
		try {
			final URL url = new URL("http://" + Util.BASE_URL + "/lithub/?model=UserPage&view=UserPageXML&action=AddBook&mobile=yes&username=" + username + "&password=" + password + "&ISBN=" + isbn);
			final SAXParserFactory spf = SAXParserFactory.newInstance();
			final SAXParser sp = spf.newSAXParser();	
			final XMLReader xr = sp.getXMLReader();	
			final AddBookHandler handler = new AddBookHandler();
			xr.setContentHandler(handler);
			Log.d(TAG, "Hitting: " + url.toString());
			xr.parse(new InputSource(url.openStream()));
		} catch (Exception e) {
			Log.e(TAG, e.getMessage());
		}		
		return true;
	}

	/**
	 * XML parser for add book return data.
	 */
	private class AddBookHandler extends DefaultHandler {

		/* (non-Javadoc)
		 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
		 */
		@Override
		public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
			Log.d(TAG, "Opening tag: " + qName);
		}

		/* (non-Javadoc)
		 * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
		 */
		@Override 
		public void characters(char ch[], int start, int length) { 
			String chars = new String(ch, start, length);
			Log.d(TAG, "Text: " + chars);
		}
	}

	/**
	 * Gets the books for self.
	 *
	 * @param username the username
	 * @param password the password
	 * @return the books for self
	 */
	public List<Book> getBooksForSelf(String username, String password) {
		try {
			final URL url = new URL("http://" + Util.BASE_URL + "/lithub/?model=UserPage&view=UserPageBooksXML&action=whatever&mobile=yes&username=" + username + "&password=" + password);
			final SAXParserFactory spf = SAXParserFactory.newInstance();
			final SAXParser sp = spf.newSAXParser();	
			final XMLReader xr = sp.getXMLReader();	
			final BookHandler handler = new BookHandler();
			xr.setContentHandler(handler);
			Log.d(TAG, "Hitting: " + url.toString());
			xr.parse(new InputSource(url.openStream()));
			return handler.getBooks();
		} catch (Exception e) {
			Log.e(TAG, e.getMessage());
		}
		return null;
	}

	/**
	 * Gets the books for user.
	 *
	 * @param user the user
	 * @return the books for user
	 */
	public List<Book> getBooksForUser(String user) {
		try {
			final URL url = new URL("http://" + Util.BASE_URL + "/lithub/?model=UserPage&view=UserPageBooksXML&action=whatever&mobile=yes&username=" + user + "&password=password");
			final SAXParserFactory spf = SAXParserFactory.newInstance();
			final SAXParser sp = spf.newSAXParser();	
			final XMLReader xr = sp.getXMLReader();	
			final BookHandler handler = new BookHandler();
			xr.setContentHandler(handler);
			Log.d(TAG, "Hitting: " + url.toString());
			xr.parse(new InputSource(url.openStream()));
			return handler.getBooks();
		} catch (Exception e) {
			Log.e(TAG, e.getMessage());
		}		
		return null;
	}

	/**
	 * XML parser for book retreival data.
	 */
	private class BookHandler extends DefaultHandler {

		/** The books. */
		private List<Book> books;
		
		/** The book. */
		private Book book;
		
		/** The in isbn. */
		private boolean inIsbn;
		
		/** The in title. */
		private boolean inTitle;
		
		/** The in author. */
		private boolean inAuthor;
		
		/** The in status. */
		private boolean inStatus;
		
		/** The in user id. */
		private boolean inUserID;
		
		/** The in owner id. */
		private boolean inOwnerID;

		/**
		 * Instantiates a new book handler.
		 */
		public BookHandler() {
			books = new ArrayList<Book>();
		}

		/**
		 * Gets the books.
		 *
		 * @return the books
		 */
		public List<Book> getBooks() {
			return books;
		}

		@Override
		public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
			inIsbn = false;
			inTitle = false;
			inAuthor = false;
			inStatus = false;
			inUserID = false;
			inOwnerID = false;

			if (qName.equals("book")) {
				book = new Book();
			} else if (qName.equals("isbn")) {
				inIsbn = true;
			} else if (qName.equals("title")) {
				inTitle = true;
			} else if (qName.equals("author")) {
				inAuthor = true;
			} else if (qName.equals("status")) {
				inStatus = true;
			} else if (qName.equals("userID")) {
				inUserID = true;
			} else if (qName.equals("ownerID")) {
				inOwnerID = true;
			}
		}

		@Override 
		public void characters(char ch[], int start, int length) { 
			if (inIsbn) {
				book.setIsbn(new String(ch, start, length));
				inIsbn = false;
			} else if (inTitle) {
				book.setTitle(new String(ch, start, length));
				inTitle = false;
			} else if (inAuthor) {
				book.setAuthor(new String(ch, start, length));
				inAuthor = false;
			} else if (inStatus) {
				book.setStatus(Integer.parseInt(new String(ch, start, length)));
				inStatus = false;
			} else if (inUserID) {
				book.setUserID(Integer.parseInt(new String(ch, start, length)));
				inUserID = false;
			} else if (inOwnerID) {
				book.setOwnerID(Integer.parseInt(new String(ch, start, length)));
				inOwnerID = false;
			}

		}
		@Override
		public void endElement(String uri, String localName, String qName) throws SAXException {
			if (qName.equals("book")) {
				books.add(book);
			}
		}
	}

	/**
	 * Gets the all friends.
	 *
	 * @param username the username
	 * @param password the password
	 * @return the all friends
	 */
	public List<Friend> getAllFriends(String username, String password) {
		try {
			final URL url = new URL("http://" + Util.BASE_URL + "/lithub/?model=UserPage&view=UserPageFriendsXML&action=whatever&mobile=yes&username=" + username + "&password=" + password);
			final SAXParserFactory spf = SAXParserFactory.newInstance();
			final SAXParser sp = spf.newSAXParser();	
			final XMLReader xr = sp.getXMLReader();	
			final GetAllFriendsHandler handler = new GetAllFriendsHandler();
			xr.setContentHandler(handler);
			Log.d(TAG, "Hitting: " + url.toString());
			xr.parse(new InputSource(url.openStream()));
			return handler.getFriends();
		} catch (Exception e) {
			Log.e(TAG, e.getMessage());
		}		
		return null;
	}

	/**
	 * XML parser for friend return data.
	 */
	private class GetAllFriendsHandler extends DefaultHandler {

		private List<Friend> friends;
		private Friend friend;
		
		private boolean inUsername;
		private boolean inUserID;

		/**
		 * Instantiates a new gets the all friends handler.
		 */
		public GetAllFriendsHandler() {
			friends = new ArrayList<Friend>();
		}

		/**
		 * Gets the list of friends.
		 *
		 * @return the friends
		 */
		public List<Friend> getFriends() {
			return friends;
		}

		@Override
		public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
			if (qName.equals("friend")) {
				friend = new Friend();
			} else if (qName.equals("username")) {
				inUsername = true;
			} else if (qName.equals("userID")) {
				inUserID = true;
			}
		}

		@Override 
		public void characters(char ch[], int start, int length) { 
			if (inUsername) {
				friend.setUsername(new String(ch, start, length));
				inUsername = false;
			} else if (inUserID) {
				friend.setUserID(Integer.parseInt(new String(ch, start, length)));
				inUserID = false;
			}
		}

		@Override
		public void endElement(String uri, String localName, String qName) throws SAXException {
			if (qName.equals("friend")) {
				friends.add(friend);
			}
		}
	}
}
